package com.example.warehousems.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.example.warehousems.component.UserInfo;
import com.example.warehousems.config.Constants;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletRequest;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;

/**
 * JWT token工具类
 */
@Slf4j
public class JwtToken {
    public static final String TOKEN_HEADER = "Authorization";
    private static final int AMOUNT = 7 * 24;

//    private static HashMap<String, String> userInfo = new HashMap<>();
    /**
     * 生成token
     *
     * @param map 意欲定义在payload中的资源
     * @return token
     */
    public static String create(HashMap<String, String> map) {
        JWTCreator.Builder builder = JWT.create();

        // 自定义超时时间
        Calendar ins = Calendar.getInstance();
        ins.add(Calendar.HOUR, AMOUNT);
//        ins.add(Calendar.MINUTE, 5);
        builder.withExpiresAt(ins.getTime());

        // 自定义payload
        map.forEach(builder::withClaim);

        // 展示token信息
        log.info("token created:" + map);

        return builder.sign(Algorithm.HMAC256(Constants.SECRET));
    }

    public static String createRefreshToken(HashMap<String, String> map) {
        JWTCreator.Builder builder = JWT.create();

        // 设置 Refresh Token 的过期时间
        Calendar ins = Calendar.getInstance();
        ins.add(Calendar.DAY_OF_MONTH, Constants.REFRESH_TOKEN_EXPIRATION_DAYS); // 设置过期时间，例如7天
        builder.withExpiresAt(ins.getTime());

        // 自定义 payload
        map.forEach(builder::withClaim);

        // 返回生成的 Refresh Token
        return builder.sign(Algorithm.HMAC256(Constants.REFRESH_TOKEN_SECRET));
    }

    public static String getNewToken(String refreshToken) {
        System.out.println(refreshToken);
        // 解码 Refresh Token
        DecodedJWT decodedRefreshToken = JWT.require(Algorithm.HMAC256(Constants.REFRESH_TOKEN_SECRET)).build().verify(refreshToken);

        // 校验 Refresh Token 是否有效
        if (decodedRefreshToken.getExpiresAt().before(new Date())) {
            throw new RuntimeException("refresh token expired");
        }

        // 从 Refresh Token 中获取用户信息
        String id = decodedRefreshToken.getClaim("id").asString();
        String username = decodedRefreshToken.getClaim("username").asString();
        String email = decodedRefreshToken.getClaim("email").asString();
        String role = decodedRefreshToken.getClaim("role").asString();

        // 根据 Refresh Token 中的信息生成新的 Access Token
        HashMap<String, String> claims = new HashMap<>();
        claims.put("id", id);
        claims.put("username", username);
        claims.put("email", email);
        claims.put("role", role);
        String newAccessToken = create(claims);

        // 将新生成的 Access Token 返回给客户端，这里可以根据需求进行操作
        return newAccessToken;
    }


    /**
     * 校验token
     *
     * @param token token
     */
    public static void verify(String token) {
        // bearer token
        if (token == null || !token.startsWith("Bearer ")) {
            throw new RuntimeException("invalid token");
        }
        token = token.substring(7);
        JWT.require(Algorithm.HMAC256(Constants.SECRET)).build().verify(token);
        // decode the token, save userinfo
        var id = JwtToken.decode(token).getClaim("id").asString();
        var username = JwtToken.decode(token).getClaim("username").asString();
        var email = JwtToken.decode(token).getClaim("email").asString();
        var role = JwtToken.decode(token).getClaim("role").asString();
        UserInfo.set("id", id);
        UserInfo.set("username", username);
        UserInfo.set("email", email);
        UserInfo.set("role", role);
    }

    /**
     * 解析token
     *
     * @param token token
     * @return DecodedJWT
     */
    public static DecodedJWT decode(String token) {
        return JWT.require(Algorithm.HMAC256(Constants.SECRET)).build().verify(token);
    }

    /**
     * 从请求头中获取token并返回解析过的token对象
     *
     * @param request 请求
     * @return 解析后的token
     */
    public static DecodedJWT acquireClaimFromHeader(HttpServletRequest request) {
        String token = request.getHeader(JwtToken.TOKEN_HEADER);
        return JwtToken.decode(token);
    }
}
